/**
 * Proxy.java
 * @author taowei20061122@163.com
 * 2013-6-9 下午4:16:40
 */
package study.designpattern.proxy.impl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import study.designpattern.proxy.UserModelApi;
import study.designpattern.proxy.bean.UserModel;

/**
 * 代理对象：实现与具体目标对象一样的接口，这样就可以使用代理来代替具体的目标对象。保存一个指向具体目标对象的引用，
 *     可以在需要的时候调用具体的目标对象。可以控制对具体目标对象的访问，并可以负责创建和删除它。
 * 
 * 场景问题：要一次访问多条数据，不让翻页。当一次访问的数据量过多，而且每条记录描述的数据量很大时，
 *     消耗的内存会比较大。
 * 解决办法：代理模式：为其他对象提供一种代理，以控制对这个对象的访问。
 * 
 * 代理的本质：控制对象访问
 * 何时选用代理模式：
 *     1.需要为一个对象在不同的地址空间提供局部代表的时候，可以使用远程代理；
 *     2.需要按照需要创建开销很大的对象的时候，可以使用虚代理（本例即是典型的虚代理）；
 *     3.需要控制对原始对象的访问的时候，可以使用保护代理；
 *     4.需要在访问对象时执行一些附加操作的时候，可以使用智能指引代理；
 * @author taowei20061122@163.com
 * 2013-6-9 下午4:16:40
 */
//public class Proxy implements Subject {
public class Proxy implements UserModelApi {

	/**
	 * 持有被代理的具体的目标对象
	 */
	private UserModelApi realSubject = null;
//	private UserModel realSubject = null;
//	private RealSubject realSubject = null;
	
	/**
	 * 构造方法，传入被代理的具体的目标对象
	 * @param realSubject 具体的被代理的目标对象
	 */
	public Proxy(UserModel userModel) {
		this.realSubject = userModel;
	}
//	public Proxy(RealSubject realSubject) {
//		this.realSubject = realSubject;
//	}
	
//	public void request() {
//		// 在转调具体的目标对象前，可以执行一些功能处理
//		
//		//转调具体的目标对象的方法
//		realSubject.request();
//
//	}
	/**
	 * 标记是否已经重新装载过数据了
	 */
	private boolean loaded = false;


	public String getUserId() {
		return realSubject.getUserId();
	}

	public String getName() {
		return realSubject.getName();
	}

	public void setUserId(String userId) {
		realSubject.setUserId(userId);
	}

	public void setName(String name) {
		realSubject.setName(name);
	}

	public void setSex(String sex) {
		realSubject.setSex(sex);
		
	}

	public void setDepId(String depId) {
		realSubject.setDepId(depId);
		
	}
	
	public String getSex() {
		//要判断是否已经装载过
		if (!loaded) {
			//从数据库重新装载
			reload();
			//设置重新加载的标志
			this.loaded = true;
			
		}
		return realSubject.getSex();
	}

	public String getDepId() {
		//要判断是否已经装载过
		if (!loaded) {
			//从数据库重新装载
			reload();
			//设置重新加载的标志
			this.loaded = true;
			
		}
		return realSubject.getDepId();
	}
	/**
	 * 重新查询数据库，以获取完整的用户数据
	 */
	public void reload() {
		System.out.println("重新查询数据库，以获取完整的用户数据，userId="+realSubject.getUserId());
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rSet = null;
		try {
			conn = this.getConnection();
			String qSql = "select * from t_user_test where userId=?";
			pstmt = conn.prepareStatement(qSql);
			pstmt.setString(1, realSubject.getUserId());
			rSet = pstmt.executeQuery();
			if (rSet.next()) {
				//只需要重新获取userId和name以外的数据
				realSubject.setDepId(rSet.getString("depId"));
				realSubject.setSex(rSet.getString("sex"));
			}
			rSet.close();
			pstmt.close();
			conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			close(rSet, pstmt, conn);
		}
	}
	/**
	 * 获取数据库连接
	 * @return
	 */
	public static Connection getConnection() {
		Connection connection = null;
		try {
			Class.forName("oracle.jdbc.OracleDriver");
			connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oradb", "pbi", "pbi");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}
	/**
	 * 释放资源
	 * @param rs
	 * @param st
	 * @param conn
	 */
	public static void close(ResultSet rs,Statement st, Connection conn) {
		try {
			if (rs!=null) {
				rs.close();
			}
			if (st!=null) {
				st.close();
			}
			if (conn!=null) {
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
